//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ProvenanceSubscriber
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.Research.ProvenanceInterfaces;
    using Microsoft.Research.DataLayer;
    using Microsoft.Practices.Unity;
    using System.Collections.ObjectModel;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using Microsoft.Research.ProvenanceSubscriberMessageParser;
    using Microsoft.Research.ProvenanceSubscriberCommon;
    using Microsoft.Research.ProvenanceSubscriberCommon.Interfaces;
    using Microsoft.Research.ProvenanceSubscriberCommon.Models;
    using Microsoft.Research.Provenance.ProvenanceDataService;

    /// <summary>
    /// This class is used to publish the provenance information to the database.
    /// </summary>
    public class ProvenancePublisher : IProvenanceSubscriber, IDisposable
    {
        /// <summary>
        /// Unity Container.
        /// </summary>
        private UnityContainer container = new UnityContainer();

        /// <summary>
        /// Provenance Service.
        /// </summary>
        private IProvenanceService provenanceService;

        /// <summary>
        /// Stores reference of the class which save teh data to DB.
        /// </summary>
        private DataStore datatStore;

        /// <summary>
        /// Starts the ProvenancePublisher.
        /// </summary>
        public void Start()
        {
            try
            {
                this.InitializeService();
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleUIException(exp);
                throw;
            }
        }

        /// <summary>
        /// Stops the ProvenancePublisher.
        /// </summary>
        public void Halt()
        {
            if (this.provenanceService != null)
            {
                this.provenanceService.StopSubscriber();
            }
        }

        /// <summary>
        /// Initialize the service.
        /// </summary>
        private void InitializeService()
        {

            this.provenanceService = this.container.Resolve<BlackboardMessageParser>();
            this.provenanceService.Start();

            datatStore = this.container.Resolve<DataStore>();
            this.provenanceService.ProvenanceMessage += new EventHandler<ProvenanceModelEventArgs>(provenanceService_ProvenanceMessage);
            this.provenanceService.InputOutputMessage += new EventHandler<ProvenanceModelEventArgs>(provenanceService_InputOutPutMessage);
            this.provenanceService.PerformanceMessage += new EventHandler<ProvenanceModelEventArgs>(provenanceService_PerformanceMessage);
            this.provenanceService.ProcessingStatusMessage += new EventHandler<ProvenanceModelEventArgs>(provenanceService_ProcessingStatusMessage);
            this.provenanceService.DataProductMessage += new EventHandler<ProvenanceModelEventArgs>(provenanceService_DataProductMessage);
        }

        /// <summary>
        /// Event handler to store the processing status information.
        /// </summary>
        /// <param name="sender">Provenance Subcriber.</param>
        /// <param name="e">ProvenanceModelEventArgs.</param>
        private void provenanceService_ProcessingStatusMessage(object sender, ProvenanceModelEventArgs e)
        {
            ProvenanceInformationModel provModel = e.ProvenanceInformationModel;
            this.datatStore.StoreProcessingStatus(provModel);
        }

        /// <summary>
        /// Event handler to store the performance information.
        /// </summary>
        /// <param name="sender">Provenance Subcriber.</param>
        /// <param name="e">ProvenanceModelEventArgs.</param>
        private void provenanceService_PerformanceMessage(object sender, ProvenanceModelEventArgs e)
        {
            ProvenanceInformationModel provModel = e.ProvenanceInformationModel;
            this.datatStore.StorePerformance(provModel);
        }

        /// <summary>
        /// Event handler to store the performance information.
        /// </summary>
        /// <param name="sender">Provenance Subcriber.</param>
        /// <param name="e">ProvenanceModelEventArgs.</param>
        private void provenanceService_DataProductMessage(object sender, ProvenanceModelEventArgs e)
        {
            ProvenanceInformationModel provModel = e.ProvenanceInformationModel;
            this.datatStore.StoreDataProduct(provModel);
        }

        /// <summary>
        /// Event handler to store the input output information.
        /// </summary>
        /// <param name="sender">Provenance Subcriber.</param>
        /// <param name="e">ProvenanceModelEventArgs.</param>
        private void provenanceService_InputOutPutMessage(object sender, ProvenanceModelEventArgs e)
        {
            ProvenanceInformationModel provModel = e.ProvenanceInformationModel;
            this.datatStore.StoreInputOutput(provModel);
        }

        /// <summary>
        /// Event handler to store the provenance information.
        /// </summary>
        /// <param name="sender">Provenance Subcriber.</param>
        /// <param name="e">ProvenanceModelEventArgs.</param>
        private void provenanceService_ProvenanceMessage(object sender, ProvenanceModelEventArgs e)
        {
            ProvenanceInformationModel provModel = e.ProvenanceInformationModel;
            this.datatStore.StoreProvenanceInfo(provModel);
        }

        #region IDisposable Members

        /// <summary>
        /// Clear.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// nullify and Disposes the object 
        /// </summary>
        /// <param name="disposing"></param>
        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.container.Dispose();
                this.container = null;
            }
        }

        #endregion
    }
}
